using OpenCvSharp;
using System;
using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;

namespace CameraManager.Models;

public partial class CameraDevice : INotifyPropertyChanged
{
    private VideoCapture? _capture;
    private bool _isRecording;
    private VideoWriter? _videoWriter;
    private string? _currentVideoFile;
    
    public int Index { get; }
    public string Name => $"Camera {Index}";
    
    private Mat? _currentFrame;
    public Mat? CurrentFrame
    {
        get => _currentFrame;
        set
        {
            _currentFrame = value;
            OnPropertyChanged(nameof(CurrentFrame));
        }
    }
    
    private bool _isRunning;
    public bool IsRunning
    {
        get => _isRunning;
        set
        {
            _isRunning = value;
            OnPropertyChanged(nameof(IsRunning));
        }
    }
    
    public bool IsRecording
    {
        get => _isRecording;
        set
        {
            _isRecording = value;
            OnPropertyChanged(nameof(IsRecording));
        }
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    public CameraDevice(int index)
    {
        Index = index;
    }

    public async Task StartAsync()
    {
        await Task.Run(() =>
        {
            try
            {
                _capture = new VideoCapture(Index);
                if (!_capture.IsOpened())
                {
                    throw new Exception($"无法打开摄像头 {Index}");
                }

                IsRunning = true;
                StartCaptureLoop();
            }
            catch (Exception ex)
            {
                throw new Exception($"启动摄像头 {Index} 失败: {ex.Message}");
            }
        });
    }

    private async void StartCaptureLoop()
    {
        while (IsRunning && _capture != null)
        {
            var frame = new Mat();
            if (_capture.Read(frame) && !frame.Empty())
            {
                CurrentFrame = frame.Clone();
                
                if (IsRecording && _videoWriter != null)
                {
                    _videoWriter.Write(frame);
                }
                
                await Task.Delay(33); // ~30 FPS
            }
        }
    }

    public async Task StopAsync()
    {
        await Task.Run(() =>
        {
            IsRunning = false;
            StopRecordingInternal();
            
            _capture?.Release();
            _capture?.Dispose();
            _capture = null;
            
            CurrentFrame?.Dispose();
            CurrentFrame = null;
        });
    }

    public void TakePicture(string filePath)
    {
        if (CurrentFrame != null && !CurrentFrame.Empty())
        {
            Cv2.ImWrite(filePath, CurrentFrame);
        }
    }

    public void StartRecording(string directory)
    {
        if (!IsRunning || _capture == null) return;

        var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
        _currentVideoFile = Path.Combine(directory, $"camera_{Index}_{timestamp}.mp4");
        
        var fps = _capture.Fps;
        if (fps <= 0) fps = 30;
        
        var frameSize = new Size(
            _capture.FrameWidth,
            _capture.FrameHeight
        );

        _videoWriter = new VideoWriter(
            _currentVideoFile,
            FourCC.MP4V,
            fps,
            frameSize
        );

        IsRecording = true;
    }

    public void StopRecording()
    {
        StopRecordingInternal();
    }

    private void StopRecordingInternal()
    {
        IsRecording = false;
        _videoWriter?.Release();
        _videoWriter?.Dispose();
        _videoWriter = null;
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
